package com.gin.web;


import com.fasterxml.jackson.databind.ObjectMapper;
import com.gin.web.dic.CheckType;
import com.gin.web.dic.WebKeys;
import com.gin.web.service.ILoginUserService;
import com.gin.web.util.WebUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.HandlerExecutionChain;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

/**
 * create  on 2020-03-13 10:23
 * 自定义拦截器
 */
public class ApiDispatcherServlet extends DispatcherServlet {

    private Logger logger = LoggerFactory.getLogger(ApiDispatcherServlet.class);

    /**
     * 获取登录信息
     */
    private ILoginUserService loginUserService;

    public ApiDispatcherServlet(WebApplicationContext webApplicationContext, ILoginUserService loginUserService) {
        super(webApplicationContext);
        this.loginUserService = loginUserService;
    }

    /**
     * 拦截请求
     *
     * @param request
     * @param response
     * @throws Exception
     */
    @Override
    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
        long start = System.currentTimeMillis();
        String url = request.getRequestURI();
        Map<String, String[]> param = request.getParameterMap();
        ObjectMapper mapper = new ObjectMapper();
        String jsonParam = mapper.writeValueAsString(param);
        String method = request.getMethod();
        String token = request.getHeader(WebKeys.AUTHORIZATION);
        logger.info("__({})-{}-(token)={} --> param = {} ------start------.", method, url, token, jsonParam);
        HandlerExecutionChain mappedHandler = this.getHandler(request);
        if (null != mappedHandler) {
            Object requestHandler = mappedHandler.getHandler();
            Map<String, String> _header = new HashMap<>();
            if (null != requestHandler && requestHandler instanceof HandlerMethod) {  // 找到了对应的controller
                HandlerMethod handler = (HandlerMethod) requestHandler;
                Class beanClz = handler.getBeanType(); // 类上面有没有注解
                LoginFlag loginFlag = (LoginFlag) beanClz.getAnnotation(LoginFlag.class);
                LoginFlag methodLoginFlag = handler.getMethodAnnotation(LoginFlag.class);
                if (null != methodLoginFlag) {
                    loginFlag = methodLoginFlag; // 用方法上的替换类上的注解
                }
                CheckType checkType = null != loginFlag ? loginFlag.checkType() : null;
                logger.info("__({})-{}-(token)={} --> param = {} , checkType = {} .", method, url, token, jsonParam, checkType);
                Map<String, String> loginUser = null;
                if (null != checkType) { // 需要登录时
                    if (checkType == CheckType.NEED_LOGIN) {
                        boolean fl = false;
                        if (WebUtil.isBlack(token)) { // token 为空
                            fl = true;
                        } else {
                            loginUser = loginUserService.getLoginUser(token);
                            if (null == loginUser) { // 验证失败，找不到用户
                                fl = true;
                            }
                        }
                        if (fl) {  // 验证失败
                            response.setStatus(401);
                            logger.info("__({})-{}-(token)={} --> param = {} , checkType = {} . 401 token 验证失败。", method, url, token, jsonParam, checkType);
                            return;
                        }
                    } else if (checkType == CheckType.READ_USER && WebUtil.isNotBlack(token)) {  // 如果需要获取用户信息
                        loginUser = loginUserService.getLoginUser(token);
                    }
                    if (null != loginUser) { // 如果获取到用户，就把用户信息放入 header 里
                        _header.putAll(loginUser);
                    }
                }
            }
            // 处理AccessType
            this.handlerAccessType(request, _header);
            // 使用自定义 HttpServletRequest
            request = new ApiRequestWrapper(request, _header);
        }
        this.doDispatch(request, response);
        logger.info("__({})-{}-(token)={} --> param = {}, 耗时 {} ------end------.", method, url, token, jsonParam, (System.currentTimeMillis() - start));
    }

    /**
     * 处理：AccessType header ，放入自定义 handler 里
     *
     * @param request
     * @param header
     */
    private void handlerAccessType(HttpServletRequest request, Map<String, String> header) {
        String accessType = request.getHeader(WebKeys.ACCESS_TYPE);
        String arr[] = new String[]{"", "", "0", ""};
        if (WebUtil.isNotBlack(accessType)) {
            // 访问类型：类型/版本号/版本/渠道。
            arr = accessType.split("/");
        }
        header.put(WebKeys.ACCESS_TYPE, accessType);
        header.put(WebKeys.AT_TYPE, arr[0]);
        header.put(WebKeys.AT_VERSION_NO, arr[1]);
        header.put(WebKeys.AT_VERSION, arr[2]);
        header.put(WebKeys.AT_CHANNEL, arr.length == 3 ? arr[0] : arr[3]);
    }

}
